/**    
 * 文件名：MySiftVisualWords.java    
 *    
 * 版本信息：    
 * 日期：2014年3月27日    
 * xyj 足下 xyj 2014     
 * 版权所有    
 *    
 */
package learn.visual.words;

import static com.googlecode.javacv.cpp.opencv_core.cvReleaseMat;
import static com.googlecode.javacv.cpp.opencv_highgui.cvLoadImage;

import java.io.File;
import java.util.List;

import org.apache.commons.io.FileUtils;

import com.googlecode.javacv.cpp.opencv_core.CvMat;
import com.googlecode.javacv.cpp.opencv_core.IplImage;
import com.googlecode.javacv.cpp.opencv_features2d.DescriptorExtractor;
import com.googlecode.javacv.cpp.opencv_features2d.KeyPoint;
import com.googlecode.javacv.cpp.opencv_nonfree.SIFT;

/**
 * @项目名称：opencv-test
 * @类名称：MySiftVisualWords
 * @类描述：
 * @创建人：zhuyi
 * @创建时间：2014年3月27日 下午3:10:22
 * @修改人：zhuyi
 * @修改时间：2014年3月27日 下午3:10:22
 * @修改备注：
 * @version
 * 
 */
public class MySiftVisualWords {

    private static int k = 500;

    private static int dims = 128;

    private static int emax = 300;

    private static String imageDir = "E:/ii";

    private static String visualWordsPath = "visualWords1";

    private static String histogramPath = "histogram300";

    public static void main(String[] args) throws Exception {

        // File dir = new File(imageDir);
        // File[] files = dir.listFiles();
        // String[] filePaths = new String[files.length];
        //
        // for (int i = 0; i < files.length; i++) {
        // filePaths[i] = files[i].getAbsolutePath();
        // }
        //
        // // 获取样本集合
        // CvMat samples = loadDescriptors(filePaths);
        //
        // // System.out.println(samples.depth());
        //
        // int featureNum = samples.rows();
        // CvMat clusters = cvCreateMat(featureNum, 1, CV_32SC1);
        // CvMat centers = cvCreateMat(k, dims, CV_32FC1);
        // // System.out.println(centers.depth());
        // cvKMeans2(samples, k, clusters, cvTermCriteria(CV_TERMCRIT_EPS +
        // CV_TERMCRIT_ITER, 10, 1.0), 3,
        // new CvRNG(null), 0, centers, null);
        //
        // // System.out.println("visual words " + centers);
        //
        // System.out.println(centers.rows());
        // System.out.println(centers.cols());
        // double[][] vss = new double[centers.rows()][dims];
        // // 遍历虚拟词
        // for (int v = 0; v < centers.rows(); v++) {
        // double[] vs = new double[dims];
        // for (int vi = 0; vi < dims; vi++) {
        // double value = 0.0d;
        // try {
        // value = centers.get(v, vi);
        // vs[vi] = value;
        // } catch (Exception e) {
        // System.out.println(v + "," + vi + "," + value);
        // e.printStackTrace();
        //
        // throw e;
        // }
        // }
        // vss[v] = vs;
        // }
        //
        // cvReleaseMat(samples);
        // cvReleaseMat(clusters);
        // cvReleaseMat(centers);
        //
        // writeVisualWordsToFile(vss);
        //
        // System.out.println(vss.length);

        // 读取视觉词典
        double[][] vss = new double[k][dims];
        List<String> vlines = FileUtils.readLines(new File(visualWordsPath));
        for (int i = 0; i < vlines.size(); i++) {
            String vline = vlines.get(i);
            String[] _vlines = vline.split("\t");
            for (int j = 0; j < _vlines.length; j++) {
                vss[i][j] = Double.parseDouble(_vlines[j]);
            }
        }

        dis(vss);

    }

    public static void writeVisualWordsToFile(double[][] visualWords) throws Exception {
        for (int i = 0; i < visualWords.length; i++) {
            double[] visualWord = visualWords[i];
            StringBuilder sb = new StringBuilder();
            for (int j = 0; j < visualWord.length; j++) {
                sb.append(visualWord[j]);
                if (j != visualWord.length - 1) {
                    sb.append("\t");
                }
            }
            sb.append("\n");
            FileUtils.writeStringToFile(new File(visualWordsPath), sb.toString(), true);
        }
    }

    public static void dis(double[][] vss) throws Exception {
        // 计算距离
        // CvMat desc = getSiftDesc(file);
        // System.out.println(desc.rows());
        // System.out.println(desc.cols());
        //
        // System.out.println(desc.depth());

        // System.out.println("desc " + desc);

        File dir = new File(imageDir);
        String[] fileNames = dir.list();
        for (String fileName : fileNames) {
            String file = imageDir + "/" + fileName;

            IplImage image = cvLoadImage(file);
            KeyPoint keyPoints = new KeyPoint();
            int nFeatures = 400;
            int nOctaveLayers = 3;
            float contrastThreshold = 0.03f;
            int edgeThreshold = 10;
            float sigma = 1.6f;
            SIFT sift = new SIFT(nFeatures, nOctaveLayers, contrastThreshold, edgeThreshold, sigma);
            DescriptorExtractor siftDesc = DescriptorExtractor.create("SIFT");
            sift.detect(image, null, keyPoints);
            CvMat desc = new CvMat(null);
            siftDesc.compute(image, keyPoints, desc);

            int[] h = new int[vss.length];
            for (int i = 0; i < vss.length; i++) {
                h[i] = 0;
            }

            for (int i = 0; i < desc.rows(); i++) {
                double[] ps = new double[dims];
                for (int j = 0; j < dims; j++) {
                    double p = desc.get(i, j);
                    ps[j] = p;
                }

                // System.out.println("ps");
                // printDoubleArray(ps);

                // 遍历虚拟词
                for (int v = 0; v < vss.length; v++) {
                    double[] vs = vss[v];
                    // System.out.println("vs");
                    // printDoubleArray(vs);
                    double d = euclid(ps, vs);
                    if (d < emax) {
                        h[v] += 1;
                    }
                }

            }

            System.out.println(file + " end");
            cvReleaseMat(desc);

            System.out.print(file + "\t");
            printIntArray(h);
            writeHistogramToFile(file, h);

            h = null;
            keyPoints = null;
            image = null;

        }

    }

    private static void writeHistogramToFile(String file, int[] histogram) throws Exception {

        FileUtils.write(new File(histogramPath), file + "\t", true);
        for (int i = 0; i < histogram.length; i++) {
            FileUtils.write(new File(histogramPath), histogram[i] + "\t", true);
        }
        FileUtils.write(new File(histogramPath), "\n", true);

    }

    public static void printDoubleArray(double[] array) {
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i] + "\t");
        }

        System.out.print("\n");
    }

    public static void printIntArray(int[] array) {
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i] + "\t");
        }

        System.out.print("\n");
    }

    public static double euclid(double[] d1, double[] d2) {
        assert d1.length == d2.length;

        double d = 0.0d;
        for (int i = 0; i < d1.length; i++) {
            double x = d1[i];
            double y = d2[i];
            d += Math.pow((x - y), 2);
        }

        return Math.sqrt(d);
    }

    public static CvMat getSiftDesc(String file) {

        IplImage image = cvLoadImage(file);
        KeyPoint keyPoints = new KeyPoint();
        int nFeatures = 400;
        int nOctaveLayers = 3;
        float contrastThreshold = 0.03f;
        int edgeThreshold = 10;
        float sigma = 1.6f;
        SIFT sift = new SIFT(nFeatures, nOctaveLayers, contrastThreshold, edgeThreshold, sigma);
        DescriptorExtractor siftDesc = DescriptorExtractor.create("SIFT");
        sift.detect(image, null, keyPoints);
        CvMat descriptors = new CvMat(null);
        siftDesc.compute(image, keyPoints, descriptors);

        return descriptors;

    }

    public static CvMat loadDescriptors(String[] files) {

        CvMat mat = null;

        for (String file : files) {

            IplImage image = cvLoadImage(file);
            KeyPoint keyPoints = new KeyPoint();
            int nFeatures = 400;
            int nOctaveLayers = 3;
            float contrastThreshold = 0.03f;
            int edgeThreshold = 10;
            float sigma = 1.6f;
            SIFT sift = new SIFT(nFeatures, nOctaveLayers, contrastThreshold, edgeThreshold, sigma);
            DescriptorExtractor siftDesc = DescriptorExtractor.create("SIFT");
            sift.detect(image, null, keyPoints);
            CvMat descriptors = new CvMat(null);
            siftDesc.compute(image, keyPoints, descriptors);

            System.out.println(file + "\t" + descriptors.rows());

            // System.out.println(descriptors.depth());
            if (mat == null) {
                mat = descriptors;
            } else {
                mat = MatCombine.combineRows(mat, descriptors);
            }

        }

        return mat;
    }
}
